#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QInputDialog>
#include <QMessageBox>
#include <QDateTime>
#include <QThread>
#include <QHostInfo>
#include <QMutex>
#include <QFile>
#include <QJsonObject>
#include <QJsonDocument>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QSslConfiguration>
#include <QJsonParseError>
#include <QFileDialog>
#include <QJsonArray>
#include <QStandardPaths>
#include <QSettings>
#include <QSerialPortInfo>
#include <QDesktopServices>


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    tcpServer = new QTcpServer(this);
    tcpSocket = new QTcpSocket(this);
    serialPort = new QSerialPort(this);
    timer = new QTimer(this);

    //Tcp
    connect(this->tcpSocket,&QTcpSocket::readyRead,this,&MainWindow::tcp_read);
    connect(this->tcpSocket,&QTcpSocket::stateChanged,this,&MainWindow::tcpStateChanged);
    connect(tcpServer,SIGNAL(newConnection()),this,SLOT(newConnection()));

    //SerialPort
    connect(this->serialPort,&QSerialPort::readyRead,this,&MainWindow::serial_read);

    //timer
    timer_start = false;
    connect(timer, SIGNAL(timeout()), this, SLOT(timer_tmout()));
    timer->start(8000);

    srv_client = NULL;

    upgrade_diaog = NULL;
    upgrade_diaog = NULL;
    manager = new QNetworkAccessManager();
    upgradesrv.set_path(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation)+"/");
    connect(&upgradesrv, &DownloadManager::download_progress, this, &MainWindow::upgrade_progress);
    connect(&upgradesrv, &DownloadManager::download_complete, this, &MainWindow::upgrade_complete);
    QTimer::singleShot(3000, this, SLOT(upgrade_check()));

    guiInitate();
}

MainWindow::~MainWindow()
{
    QSettings *config = new QSettings("serial2net.ini", QSettings::IniFormat);

    config->setValue("/serial/com", ui->portCombox->currentText());
    config->setValue("/serial/baud", ui->bodeCombox->currentText());
    config->setValue("/net/ip", ui->ipEdit->text());
    config->setValue("/net/port", ui->portEdit->text());
    config->setValue("/net/type", ui->typeCombox->currentText() == "客户端" ? "client" : "server");
    config->sync();

    delete tcpServer;
    delete tcpSocket;
    delete serialPort;
    delete timer;
    delete ui;
    delete config;
}

//界面初始化
void MainWindow::guiInitate()//界面填充
{
    QSettings *config = new QSettings("serial2net.ini", QSettings::IniFormat);

    //设置串口
    QList<QSerialPortInfo> portList=QSerialPortInfo::availablePorts();
    if(!portList.isEmpty())
    {
        QString com = config->value("/serial/com").toString();
        ui->openSerialButton->setEnabled(true);
        foreach (QSerialPortInfo port, portList) {
            ui->portCombox->addItem(port.portName());
            if (!com.isEmpty() && com == port.portName()) {
                ui->portCombox->setCurrentIndex(ui->portCombox->count()-1);
            }
        }
    }
    else
    {
        ui->openSerialButton->setEnabled(false);
    }


    //设置波特率
    QList<qint32> bodeList=QSerialPortInfo::standardBaudRates();
    QString baud = config->value("/serial/baud").toString();
    foreach (qint32 bode, bodeList) {
        ui->bodeCombox->addItem(QString::number(bode));
        if (bode == baud.toInt()) {
            ui->bodeCombox->setCurrentIndex(ui->bodeCombox->count()-1);
        }
    }

    //初始化网络
    ui->ipEdit->setText("127.0.0.1");
    ui->portEdit->setText("9810");
    QString ip = config->value("/net/ip").toString();
    QString port = config->value("/net/port").toString();
    if (!ip.isEmpty()) {
        ui->ipEdit->setText(ip);
    }
    if (!port.isEmpty()) {
        ui->portEdit->setText(port);
    }

    //其他配置
    QString net_tyep = config->value("/net/type").toString();
    if (!net_tyep.isEmpty() && net_tyep == "server") {
        ui->typeCombox->setCurrentIndex(1);
        ui->ipEdit->setEnabled(false);
    }

    delete config;
}

void MainWindow::on_openSerialButton_clicked()
{
    //打开串口
    if(ui->openSerialButton->text()=="打开串口")
     {
        //端口名
        QString portName=ui->portCombox->currentText();

        //波特率
        qint32  baudRate=ui->bodeCombox->currentText().toInt();

        //数据位
        QSerialPort::DataBits dataBits = QSerialPort::Data8;

        //停止位
        QSerialPort::StopBits stopBits = QSerialPort::OneStop;

        //校验位
        QSerialPort::Parity parity = QSerialPort::NoParity;

        serialPort->setPortName(portName);

        if(serialPort->open(QIODevice::ReadWrite))
        {
            serialPort->setBaudRate(baudRate);
            serialPort->setDataBits(dataBits);
            serialPort->setStopBits(stopBits);
            serialPort->setParity(parity);
            ui->openSerialButton->setText("关闭串口");
            ui->serialBtn->setEnabled(true);
            ui->textBrowser->clear();
            ui->textBrowser->append("打开串口成功！");
        }
    //关闭串口
    } else {
        serialPort->close();
        ui->openSerialButton->setText("打开串口");
        ui->serialBtn->setEnabled(false);
        ui->textBrowser->append("关闭串口成功！");
    }
}

//网络按钮
void MainWindow::on_openTcpButton_clicked()
{
    ui->textBrowser->clear();

    if(ui->openTcpButton->text()=="关闭网络") {
        ui->typeCombox->setEnabled(true);
        if(ui->typeCombox->currentText() == "服务器") {
            if (srv_client) {
                srv_client->close();
                srv_client->abort();
                delete srv_client;
                srv_client = NULL;
            }

            tcpServer->close();
            ui->textBrowser->append("取消监听");
            ui->ipEdit->setEnabled(false);
            ui->portEdit->setEnabled(true);
        } else {
            tcpSocket->disconnectFromHost();
            tcpSocket->close();
            tcpSocket->abort();
            ui->textBrowser->append("从主机断开！");
            ui->ipEdit->setEnabled(true);
            ui->portEdit->setEnabled(true);
        }

        ui->openTcpButton->setText("打开网络");
        ui->tcpStateBtn->setEnabled(false);
        return;
    } else {

         ui->ipEdit->setEnabled(false);
         ui->portEdit->setEnabled(false);
         ui->typeCombox->setEnabled(false);

        //连接网络
        if(ui->typeCombox->currentText() == "服务器")  {
            tcpServer->close();

            //监听
            if( !tcpServer->listen(QHostAddress::Any, ui->portEdit->text().toInt()) ){
                ui->textBrowser->append(QString("listen error: %1").arg(tcpServer->errorString()));
                return;
            }

            tcpServer->setMaxPendingConnections(1);//设置最大允许连接数

        } else {
            ui->textBrowser->clear();
            tcpSocket->abort();
            tcpSocket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
            tcpSocket->connectToHost(ui->ipEdit->text(),ui->portEdit->text().toInt());
        }
        ui->openTcpButton->setText("关闭网络");
    }
}

//新的客户端连接
void MainWindow::newConnection()
{
    QTcpSocket *tcp = tcpServer->nextPendingConnection();

    if (srv_client) {
        tcp->close();
        tcp->abort();
        delete tcp;
        return;
    }

    srv_client = tcp;
    ui->textBrowser->append("client ip:"+ srv_client->peerAddress().toString());

    //设置接收函数
    connect(srv_client,SIGNAL(readyRead()),this,SLOT(tcp_read()));
    ui->tcpStateBtn->setEnabled(true);
}

void MainWindow::tcp_read()
{
    QTcpSocket *socket = (ui->typeCombox->currentText()=="客户端") ? tcpSocket : srv_client;
    qint64 length = socket->bytesAvailable();
    qint64 nRec=0;

    if(length >= 1) {
        char temp[length];
        nRec = socket->read(temp,length);
//        ui->textBrowser->append(QString("网络收到%1个数据").arg(nRec));
        ui->textBrowser->append(QString("<[%1]%2").arg(QTime::currentTime().toString("hh:mm:ss.zzz")).arg(QString::fromLocal8Bit(temp, length)));

        serialPort->write(temp,nRec);
    }
}

void MainWindow::serial_read()
{
    qint64 nRec=0;
    qint64 length=serialPort->bytesAvailable();
    QTcpSocket *socket = (ui->typeCombox->currentText()=="客户端") ? tcpSocket : srv_client;

    if(length >= 1) {
        char temp[length];
        nRec = serialPort->read(temp,length);
//        ui->textBrowser->append(QString("串口收到%1个数据").arg(nRec));
        ui->textBrowser->append(QString(">[%1]%2").arg(QTime::currentTime().toString("hh:mm:ss.zzz")).arg(QString::fromLocal8Bit(temp, length)));
        if (socket) {
            socket->write(temp,nRec);
        }
    }
}

void MainWindow::tcpStateChanged(QAbstractSocket::SocketState socketState)
{
    switch(socketState)
    {
     case QAbstractSocket::UnconnectedState:
        ui->textBrowser->append("Tcp网络未连接！");
        break;
    case QAbstractSocket::HostLookupState:
        ui->textBrowser->append("寻找服务主机中...");
        break;
    case QAbstractSocket::ConnectingState:
        ui->textBrowser->append("找到服务主机！");
        ui->textBrowser->append("Tcp网络连接中...");
        break;
    case QAbstractSocket::ConnectedState:
        ui->textBrowser->append("Tcp网络已连接！");
        break;
    case QAbstractSocket::ClosingState:
        ui->textBrowser->append("Tcp网络准备关闭中...");
        break;
    default:
        break;
    }

    if (tcpSocket->state() == QAbstractSocket::ConnectedState) {
       ui->tcpStateBtn->setEnabled(true);
    } else {
       ui->tcpStateBtn->setEnabled(false);

       //客户端断开连接,删除socket
       if (ui->typeCombox->currentText()=="服务器" && srv_client) {
            srv_client->abort();
            delete srv_client;
            srv_client = NULL;
            ui->textBrowser->append("客户端断开");
       }
    }
}

//定时器
void MainWindow::timer_tmout()
{
    //连接断开，重新连接
    if (tcpSocket->state() != QAbstractSocket::ConnectedState &&
        tcpSocket->state() != QAbstractSocket::ConnectingState &&
        ui->typeCombox->currentText()=="客户端" &&
        ui->openTcpButton->text() == "关闭网络") {
        tcpSocket->abort();
        tcpSocket->connectToHost(ui->ipEdit->text(),ui->portEdit->text().toInt());
    }
}



void MainWindow::on_typeCombox_currentIndexChanged(const QString &arg1)
{
    (void)arg1;
    if (ui->typeCombox->currentText() == "客户端") {
        ui->ipEdit->setEnabled(true);
    } else {
        ui->ipEdit->setEnabled(false);
    }
}

void MainWindow::on_action_triggered()
{
    QMessageBox::information(this,tr("软件信息"),QString("当前版本号：%1").arg(cur_version));
}

QNetworkReply* MainWindow::https_req(QNetworkRequest&  req,
                                     const QString&    method,
                                     const QByteArray& content,
                                     uint32_t          tmout)
{
    QNetworkReply* p_reply = NULL;

    //ssl设置
    QSslConfiguration conf = req.sslConfiguration();
    conf.setPeerVerifyMode(QSslSocket::VerifyNone);
    conf.setProtocol(QSsl::TlsV1SslV3);
    req.setSslConfiguration(conf);

    if (method == "post") {
        p_reply = manager->post(req, content);
    } else if (method == "put") {
        p_reply = manager->put(req, content);
    } else if (method == "get") {
        p_reply = manager->get(req);
    } else {
        return NULL;
    }

    qint64 time = QDateTime::currentMSecsSinceEpoch();
    while(1) {
        //超时退出
        if (QDateTime::currentMSecsSinceEpoch() > (time + tmout)) {
             break;
        }

        //处理其他信息
        QCoreApplication::processEvents(QEventLoop::AllEvents,1000);

        if (p_reply->isFinished()) {
            break;
        }
    }

    //请求已经结束，向上返回
    if (p_reply->isFinished()) {
        return p_reply;
    }

    //请求超时，自动删除
    p_reply->deleteLater();

    return NULL;
}

//获取下载信息
int MainWindow::download_info(const QString& product, QString *p_name, QString *p_version, QString *p_path, QString *p_md5)
{
    QString mode = "production_package";
    QNetworkReply* p_reply = NULL;
    QNetworkRequest request;

    request.setUrl(QString("http://api-dev.renjinggai.com:10083/applications/%1/").arg(product));
    p_reply = https_req(request, "get", NULL, 5000);
    if (p_reply == NULL) {
        QMessageBox::critical(this,
                             QString("获取软件信息超时"),
                             QString("获取软件信息超时，请检查网路！"));
        return -1;
    }

    if (p_reply->error() != QNetworkReply::NoError) {
        QMessageBox::critical(this,
                              QString("获取软件信息失败"),
                              QString("获取软件信息失败，请稍后重试！"));
        p_reply->deleteLater();
         return -2;
    }

    QJsonParseError error;
    QJsonDocument json_doc = QJsonDocument::fromJson(p_reply->readAll(),&error);
    QJsonObject json_obj = json_doc.object().value(mode).toObject();

    if (json_obj.empty() ||
       !json_obj.contains("version") ||
       !json_obj.contains("file_name") ||
       !json_obj.contains("file") ||
       !json_obj.contains("md5")) {
        return -3;
    }

    if (p_name) {
         *p_name = json_obj.value("file_name").toString();
    }
    if (p_version) {
        *p_version = json_obj.value("version").toString();
    }
    if (p_path) {
        *p_path = json_obj.value("file").toString();
    }
    if (p_md5) {
        *p_md5 = json_obj.value("md5").toString();
    }

    return 0;
}

//检查升级
void MainWindow::upgrade_check()
{
    QString name;
    QString version;
    QString path;
    QString md5;

    int ret = download_info("serial2net", &name, &version, &path, &md5);
    if (ret != 0) {
        QMessageBox::critical(this,
                             QString("检查更新"),
                             QString("获取升级文件信息失败，请检查网络！"));
        return;
    }

     if (version == cur_version) {
         ui->textBrowser->append("检查更新:程序已经为最新版本！");
         return;
     }

     QMessageBox::StandardButton btn =
     QMessageBox::question(this,
                           QString("发现新版本"),
                           QString("当前版本：%1\n最新版本：%2\n是否更新？").arg(cur_version).arg(version));

     if (btn != QMessageBox::Yes) {
         return;
     }

     upgradesrv.add_download(QUrl(path));

     upgrade_diaog = new QProgressDialog(this);
     upgrade_diaog->setModal(true);
     upgrade_diaog->setCancelButton(NULL);
     upgrade_diaog->setRange(0,100);
     upgrade_diaog->setLabelText("正在下载升级文件...");
     upgrade_diaog->show();
     upgrade_diaog->setModal(true);
}

//下载进度
void MainWindow::upgrade_progress(const QUrl &url, qint64 bytesReceived, qint64 bytesTotal)
{
    (void)url;

    if (upgrade_diaog && bytesTotal != 0) {
        upgrade_diaog->setValue(100*bytesReceived/bytesTotal);
    }
}

//下载完成
void MainWindow::upgrade_complete(const QUrl &url, bool ok, const QString file_name)
{
    (void)url;

    if (upgrade_diaog) {
        upgrade_diaog->hide();
        upgrade_diaog->deleteLater();
        upgrade_diaog = NULL;
    }

    if (!ok) {
        QMessageBox::critical(this,
                             QString("下载安装文件失败"),
                             QString("下载安装文件失败！"));
        return;
    }

    QDesktopServices::openUrl(file_name);
}

/* end file */
